﻿#region File Description
/****************************************************************************
*                                                                           *
* Game Manager.                                                             *
*                                                                           *
* Copyright (c) Ionescu Marius. All rights reserved(2013).                  *
*                                                                           *
****************************************************************************/
#endregion
namespace Silverlight3D
{
    using System;

    /// <summary>
    /// Comprises two vectors representing a 3D Position and 3D Velocity.
    /// </summary>
    public class Vertex
    {
        #region Properties

        public const int MaxPower = 500;
        private static double[] DampFactorXZ { get; set; }
        private static double[] DampFactorY { get; set; }

        public Vector Position { get; set; }
        public Vector Velocity { get; set; }

        public double X { get { return Position.X; } set { Position.X = value; } }
        public double Y { get { return Position.Y; } set { Position.Y = value; } }
        public double Z { get { return Position.Z; } set { Position.Z = value; } }

        #endregion

        #region Constructors

        public Vertex()
        {
            Position = new Vector();
            Velocity = new Vector();
        }

        /// <summary>
        /// Instantiates a Vertex with give XYZ position.  Velocity is zero.
        /// </summary>
        /// <param name="x">Position X coordinate.</param>
        /// <param name="y">Position Y coordinate.</param>
        /// <param name="z">Position Z coordinate.</param>
        public Vertex(double x, double y, double z)
        {
            Position = new Vector(x, y, z);
            Velocity = new Vector();
        }

        #endregion

        #region Public methods

        /// <summary>
        /// Sets up the static array of damp factors.  Each entry in the array contains the
        /// passed damp factors, raised to the power of the array index.  This avoids having to
        /// use Math.Pow() whenever a power is required.  X and Z velocity components have one damp
        /// factor, and Y components have their own damp factor.
        /// </summary>
        /// <param name="dampFactorXZ">The damp factor for X and Z values.</param>
        /// <param name="dampFactorY">The damp factor for Y values.</param>
        public static void SetDampFactor(double dampFactorXZ, double dampFactorY)
        {
            DampFactorXZ = new double[MaxPower + 1];
            DampFactorY = new double[MaxPower + 1];

            for (int i = 0; i <= MaxPower; i++)
            {
                DampFactorXZ[i] = Math.Pow(dampFactorXZ, i);
                DampFactorY[i] = Math.Pow(dampFactorY, i);
            }
        }

        /// <summary>
        /// Update the Vertex Position based on its Velocity.
        /// </summary>
        public void Update()
        {
            Position += Velocity * 4;
        }

        #endregion

        #region Attraction methods

        /// <summary>
        /// Adjust Vertex's delta to attract towards a given Vertex's position.
        /// </summary>
        /// <param name="other">The Vertex whose position to attract towards.</param>
        /// <param name="strength">The strength of the attraction.</param>
        public void AttractTowards(Vertex other, double strength)
        {
            AttractTowards(other.Position, strength);
        }

        /// <summary>
        /// Adjust Vertex's Delta to attract towards a given position specified by a Vector.
        /// </summary>
        /// <param name="other">The Vector specifying the position to attract towards.</param>
        /// <param name="strength">The strength of the attraction.</param>
        public void AttractTowards(Vector other, double strength)
        {
            Vector direction = other - this.Position;

            direction = VectorHelper.Normalise(direction);

            Velocity += direction * strength;
        }

        #endregion

        #region Repulsion methods

        /// <summary>
        /// Adjust Vertex's delta to repel away from a given Vertex's position.
        /// </summary>
        /// <param name="other">The Vertex whose position to repel away from.</param>
        /// <param name="strength">The strength of the repulsion.</param>
        public void RepelAwayFrom(Vertex other, double strength)
        {
            AttractTowards(other.Position, -strength);
        }

        /// <summary>
        /// Adjust Vertex's delta to repel away from a given position specified by a Vector.
        /// </summary>
        /// <param name="other">The Vector specifying the position to repel away from.</param>
        /// <param name="strength">The strength of the repulsion.</param>
        public void RepelAwayFrom(Vector other, double strength)
        {
            AttractTowards(other, -strength);
        }

        /// <summary>
        /// Immediately move Vertex's Position away from a given position specified by a Vector.
        /// </summary>
        /// <param name="other">The Vector specifying the position to move away from.</param>
        /// <param name="strength">The proportion of the current difference in position to add to the current position.</param>
        public void MoveAwayFrom(Vector other, double strength)
        {
            Position += (this.Position - other) * strength;
        }

        #endregion

        #region Damping methods

        /// <summary>
        /// Damp the Vertex's Delta by multiplying each component by a given factor.
        /// </summary>
        /// <param name="factorXZ">The factor to multiply the X and Z components by.</param>
        /// <param name="factorY">The factor to multiply the Y component by.</param>
        public void Damp(int power)
        {
            Velocity.X = Velocity.X * DampFactorXZ[power];
            Velocity.Y = Velocity.Y * DampFactorY[power];
            Velocity.Z = Velocity.Z * DampFactorXZ[power];
        }

        /// <summary>
        /// Damp the Vertex's Delta Y component by multiplying it by DampFactorY.
        /// </summary>
        /// <param name="power">Settings.DampFactorY is raised to this power.</param>
        public void DampY(int power)
        {
            Velocity.Y = Velocity.Y * DampFactorY[power];
        }

        #endregion
    }
}